package com.premnirmal.magnet.library;

import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringListener;
import com.facebook.rebound.SpringSystem;
import com.tumblr.Actor;
import com.tumblr.MotionProperty;
import com.tumblr.backboard.imitator.Imitator;
import com.tumblr.backboard.imitator.InertialImitator;
import com.tumblr.performer.Performer;
import cs.help.tool.Log;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.Component;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.StackLayout;
import ohos.agp.components.element.Element;
import ohos.agp.utils.Rect;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.agp.window.service.Window;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
import ohos.event.commonevent.*;
import ohos.multimodalinput.event.TouchEvent;
import ohos.rpc.RemoteException;

import java.math.BigDecimal;


/**
 * Created by prem on 7/20/14.
 * Class that holds the Magnet icon, and performs touchEvents on the view.
 */
public class Magnet implements SpringListener, Component.TouchEventListener, Component.ClickedListener, Component.LayoutRefreshedListener {

    @Override
    public void onRefreshed(Component component) {
        xMinValue = -iconView.getEstimatedHeight() * hideFactor;
        motionImitatorX.setMinValue(xMinValue);
        xMaxValue = BigDecimal.valueOf(getDisplayWidthInPx(context)).subtract(
                BigDecimal.valueOf(1).subtract(BigDecimal.valueOf(hideFactor)).multiply(BigDecimal.valueOf(iconView.getEstimatedWidth()))
        ).floatValue();
        motionImitatorX.setMaxValue(xMaxValue);
        yMinValue = BigDecimal.valueOf(getStatusBarHeight()).subtract(
                BigDecimal.valueOf(iconView.getEstimatedHeight()).multiply(BigDecimal.valueOf(hideFactor))
        ).floatValue();
        motionImitatorY.setMinValue(yMinValue);
        yMaxValue = BigDecimal.valueOf(getDisplayHightInPx(context))
                .subtract(BigDecimal.valueOf(getNavBarHeight()))
                .add(BigDecimal.valueOf(hideFactor).multiply(BigDecimal.valueOf(iconView.getEstimatedHeight())))
                .floatValue();
        motionImitatorY.setMaxValue(yMaxValue);
        iconView.setLayoutRefreshedListener(null);
        goToWall();
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        int action = event.getAction();
        if (action == TouchEvent.PRIMARY_POINT_DOWN) {
            isBeingDragged = true;
            lastTouchDown = System.currentTimeMillis();
            return true;
        } else if (action == TouchEvent.OTHER_POINT_UP || action == TouchEvent.CANCEL) {
            isBeingDragged = false;
            return true;
        }
        return false;
    }


    @Override
    public void onSpringUpdate(Spring spring) {
    }

    @Override
    public void onSpringAtRest(Spring spring) {

    }

    @Override
    public void onSpringActivate(Spring spring) {

    }

    @Override
    public void onSpringEndStateChange(Spring spring) {

    }

    /**
     * Builder class to create your {@link Magnet}
     */
    public static class Builder {

        protected Magnet magnet;

        public Builder(Context context) {
            magnet = new Magnet(context);
        }

        /**
         * The Icon must have a view, provide a view or a layout using {@link #setIconView(int)}
         *
         * @param iconView the view representing the icon
         * @return Builder
         */
        public Builder setIconView(Component iconView) {
            magnet.iconView = iconView;
            return this;
        }

        /**
         * Use an xml layout to provide the button view
         *
         * @param iconViewRes Use an xml layout to provide the button view
         * @return Builder
         */
        public Builder setIconView(int iconViewRes) {
            return setIconView(LayoutScatter.getInstance(magnet.context).parse(iconViewRes, null, false));
        }

        /**
         * whether your magnet sticks to the edge your screen when you release it
         *
         * @param shouldStick hether your magnet sticks to the edge your screen when you release it
         * @return Builder
         */
        public Builder setShouldStickToWall(boolean shouldStick) {
            magnet.shouldStickToWall = shouldStick;
            return this;
        }

        /**
         * Whether you can fling away your Magnet towards the bottom of the screen
         *
         * @param shouldFling Whether you can fling away your Magnet towards the bottom of the screen
         * @return Builder
         * @deprecated use {@link #setShouldShowRemoveView(boolean)} instead
         */
        @Deprecated
        public Builder setShouldFlingAway(boolean shouldFling) {
            return this;
        }


        /**
         * Set callback.
         *
         * @param callback Callback for when the icon moves, is clicked, is flinging away, and destroyed
         * @return Builder
         */
        public Builder setIconCallback(IconCallback callback) {
            magnet.iconCallback = callback;
            return this;
        }


        /**
         * Set whether the remove icon should be shown.
         *
         * @param showRemoveView Whether the remove icon should be shown
         * @return Builder
         */
        public Builder setShouldShowRemoveView(boolean showRemoveView) {
            magnet.shouldShowRemoveView = showRemoveView;
            return this;
        }


        /**
         * Whether the remove icon should respond to touch movements
         *
         * @param shouldBeResponsive Whether the remove icon should respond to touch movements
         * @return Builder
         */
        public Builder setRemoveIconShouldBeResponsive(boolean shouldBeResponsive) {
            magnet.removeView.shouldBeResponsive = shouldBeResponsive;
            return this;
        }


        /**
         * You can set a custom remove icon or use the default one
         *
         * @param removeIconResId Removeview icon id
         * @return Builder
         */
        public Builder setRemoveIconResId(Element removeIconResId) {
            magnet.removeView.setIconResId(removeIconResId);
            return this;
        }


        /**
         * You can set a custom remove icon shadow or use the default one
         *
         * @param shadow Removeview icon
         * @return Builder
         */
        public Builder setRemoveIconShadow(Element shadow) {
            magnet.removeView.setShadowBG(shadow);
            return this;
        }

        /**
         * Set the initial coordinates of the magnet in pixels
         *
         * @param locX x-axis initial coordinate
         * @param locY y-axis initial coordinate
         * @return Builder
         */
        public Builder setInitialPosition(int locX, int locY) {
            magnet.initialX = locX;
            magnet.initialY = locY;
            return this;
        }

        /**
         * Set a custom width for the icon view in pixels. default is {@link
         *
         * @param width width for the icon view in pixels
         * @return Builder
         */
        public Builder setIconWidth(int width) {
            magnet.iconWidth = width;
            return this;
        }

        /**
         * Set a custom height for the icon view in pixels. default is {@link
         *
         * @param height height for the icon view in pixels
         * @return Builder
         */
        public Builder setIconHeight(int height) {
            magnet.iconHeight = height;
            return this;
        }

        /**
         * Set the percent of the view to be hidden when the magnet touches the wall. Default is {@code
         * 0.3f}.
         *
         * @param toHideFactor the percent of the view to be hidden
         * @return Builder
         */
        public Builder setHideFactor(float toHideFactor) {
            magnet.hideFactor = toHideFactor;
            return this;
        }

        /**
         * Set the configuration for the springs used by this magnet.
         *
         * @param springConfig configuration for the springs
         * @return Builder
         */
        public Builder withSpringConfig(SpringConfig springConfig) {
            magnet.springConfig = springConfig;
            return this;
        }

        public Magnet build() {
            if (magnet.iconView == null) {
                throw new NullPointerException("IconView is null!");
            }
            return magnet;
        }
    }

    protected static double distSq(double x1, double y1, double x2, double y2) {
        return Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);
    }

    protected Component iconView;
    protected RemoveView removeView;
    protected WindowManager windowManager;
    protected WindowManager.LayoutConfig layoutParams;
    protected Context context;
    protected IconCallback iconCallback;
    protected final CommonEventSubscriber orientationChangeReceiver;

    protected SpringConfig springConfig;
    protected Spring xSpring;
    protected Spring ySpring;
    protected Actor actor;
    protected MagnetImitator motionImitatorX;
    protected MagnetImitator motionImitatorY;
    protected WindowManagerPerformer xWindowManagerPerformer;
    protected WindowManagerPerformer yWindowManagerPerformer;
    protected float hideFactor = 0.3f;
    protected float xMinValue;
    protected float xMaxValue;
    protected float yMinValue;
    protected float yMaxValue;
    protected int iconWidth = -1;
    protected int iconHeight = -1;
    protected int initialX = -1;
    protected int initialY = -1;
    protected int[] iconPosition = new int[]{0, 0};

    protected boolean shouldShowRemoveView = true;
    protected float goToWallVelocity;
    protected float flingVelocityMinimum;
    protected float restVelocity;
    protected boolean shouldStickToWall = true;
    protected long lastTouchDown;
    protected boolean isBeingDragged;
    protected boolean addedToWindow;
    protected boolean isFlinging;
    protected boolean isGoingToWall;

    public Magnet(Context context) {
        this.context = context;
        MatchingSkills matchingSkills = new MatchingSkills();
        matchingSkills.addEvent("android.intent.action.CONFIGURATION_CHANGED");
        CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
        orientationChangeReceiver = new OrientationChangeReceiver(subscribeInfo);
        windowManager = WindowManager.getInstance();
        removeView = new RemoveView(context);
        goToWallVelocity = pxFromDp((float) (getDisplayWidthInPx(context) * 1.5));
        flingVelocityMinimum = pxFromDp((float) (getDisplayHightInPx(context) * 1.5));
        restVelocity = pxFromDp(400);
        springConfig = SpringConfig.fromBouncinessAndSpeed(1, 20);
    }

    public RemoveView getRemoveView() {
        return removeView;
    }

    protected SpringSystem getSpringSystem() {
        return SpringSystem.create();
    }


    protected SpringConfig getSpringConfig() {
        return springConfig;
    }

    protected Spring createXSpring(SpringSystem springSystem, SpringConfig config) {
        Spring spring = springSystem.createSpring();
        spring.setSpringConfig(config);
        spring.setRestSpeedThreshold(restVelocity);
        return spring;
    }

    protected Spring createYSpring(SpringSystem springSystem, SpringConfig config) {
        Spring spring = springSystem.createSpring();
        spring.setSpringConfig(config);
        spring.setRestSpeedThreshold(restVelocity);
        return spring;
    }

    protected void initializeMotionPhysics() {
        SpringConfig config = getSpringConfig();
        SpringSystem springSystem = getSpringSystem();
        xSpring = createXSpring(springSystem, config);
        ySpring = createYSpring(springSystem, config);
        motionImitatorX =
                new MagnetImitator(MotionProperty.X, Imitator.TRACK_ABSOLUTE, Imitator.FOLLOW_SPRING, 0, 0);
        motionImitatorY =
                new MagnetImitator(MotionProperty.Y, Imitator.TRACK_ABSOLUTE, Imitator.FOLLOW_SPRING, 0, 0);
        xWindowManagerPerformer = new WindowManagerPerformer(MotionProperty.X);
        yWindowManagerPerformer = new WindowManagerPerformer(MotionProperty.Y);
        actor = new Actor.Builder(springSystem, iconView).addMotion(xSpring, motionImitatorX,
                xWindowManagerPerformer)
                .addMotion(ySpring, motionImitatorY, yWindowManagerPerformer)
                .onTouchListener(this)
                .build();
        iconView.setLayoutRefreshedListener(this);
    }

    protected int getStatusBarHeight() {
        int result = AttrHelper.vp2px(24, context);
        return result;
    }

    protected int getNavBarHeight() {
        int result = AttrHelper.vp2px(40, context);
        return result;
    }

    Window window;


    protected void addToWindow(Context context) {
        StackLayout stackLayout = new StackLayout(context);
        stackLayout.addComponent(iconView, StackLayout.LayoutConfig.MATCH_CONTENT, StackLayout.LayoutConfig.MATCH_CONTENT);
        window = WindowManager.getInstance().addComponent(stackLayout, context, WindowManager.LayoutConfig.MOD_APPLICATION_OVERLAY);
        window.setMovable(true);
        layoutParams = new WindowManager.LayoutConfig();
        layoutParams.height = 500;
        layoutParams.width = 500;
        layoutParams.flags = WindowManager.LayoutConfig.MARK_FOCUSABLE_IMPOSSIBLE;
        layoutParams.alignment = (1 | 2 << 4) | (1 | 2 << 0);
        window.setLayoutConfig(layoutParams);
        window.setTransparent(true);


        context.getMainTaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                if (window != null && stackLayout.getEstimatedWidth() != 0) {
                    layoutParams.width = stackLayout.getEstimatedWidth();
                    layoutParams.height = stackLayout.getEstimatedHeight();
                    layoutParams.flags = WindowManager.LayoutConfig.MARK_FOCUSABLE_IMPOSSIBLE;
                    layoutParams.alignment = (1 | 2 << 4) | (1 | 2 << 0);
                    layoutParams.x = initialX;
                    layoutParams.y = initialY;
                    window.setLayoutConfig(layoutParams);
                    window.setTransparent(true);
                }
            }
        }, 10);

        addedToWindow = true;
    }

    protected float pxFromDp(float dp) {
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        final float scale = display.getAttributes().densityPixels;
        return (int) (dp / scale + 0.5);
    }

    protected boolean iconOverlapsWithRemoveView() {
        try {
            if (removeView.isShowing()) {

                int[] hideView = removeView.getButtonImage().getLocationOnScreen();
                if (removeView.getWindow().getLayoutConfig().isPresent()) {
                    WindowManager.LayoutConfig removeViewWindowLayoutConfig = removeView.getWindow().getLayoutConfig().get();
                    hideView[0] = hideView[0] + removeViewWindowLayoutConfig.x;
                    hideView[1] = hideView[1] + removeViewWindowLayoutConfig.y;
                }
                WindowManager.LayoutConfig windowLayoutConfig = window.getLayoutConfig().get();

                // Rect constructor parameters: left, top, right, bottom
                Rect rectFirstView = new Rect(hideView[0], hideView[1], hideView[0] + removeView.getButtonImage().getEstimatedWidth(), hideView[1] + removeView.getButtonImage().getEstimatedHeight());
                Rect rectSecondView = new Rect(windowLayoutConfig.x, windowLayoutConfig.y,
                        windowLayoutConfig.x + windowLayoutConfig.width,
                        windowLayoutConfig.y + windowLayoutConfig.height);
                return rectFirstView.getIntersectRect(rectSecondView);
            }
        } catch (Exception e) {
            Log.i("Magnet.iconOverlapsWithRemoveView([]):392   " + e.getMessage());
            return false;
        }
        return false;
    }

    protected void showRemoveView() {
        if (removeView != null && shouldShowRemoveView && !removeView.isShowing()) {
            removeView.show();
        }
    }

    protected void hideRemoveView() {
        if (removeView != null && shouldShowRemoveView && removeView.isShowing()) {
            removeView.hide();
        }
    }

    protected void onOrientationChange() {
        iconView.setLayoutRefreshedListener(Magnet.this);
    }


    /**
     * Move the icon to the given position
     *
     * @param x       The x coordinate to move to in pixels
     * @param y       The y coordinate to move to in pixels
     * @param animate Whether to animate to the position. This param is deprecated and will be
     *                ignored
     * @deprecated use {@link #setPosition(int, int)}
     */
    @Deprecated
    public void setPosition(int x, int y, boolean animate) {
        setPosition(x, y);
    }

    /**
     * Move the icon to the given position
     *
     * @param locX The x coordinate to move to in pixels
     * @param locY The y coordinate to move to in pixels
     */
    public void setPosition(int locX, int locY) {
        actor.removeAllListeners();
        xSpring.setEndValue(locX);
        ySpring.setEndValue(locY);
        actor.addAllListeners();
    }

    /**
     * Update the icon view size after the magnet has been shown
     *
     * @param width  the width of the icon view in pixels
     * @param height the height of the icon view in pixels
     */
    public void setIconSize(int width, int height) {
        iconWidth = width;
        iconHeight = height;
        if (addedToWindow) {
            layoutParams.width = width;
            layoutParams.height = height;
            window.setLayoutConfig(layoutParams);
        }
    }

    /**
     * Show the Magnet i.e. add it to the Window
     */
    public void show() {
        if (window == null) {
            addToWindow(context);
            iconView.setClickedListener(this);
            initializeMotionPhysics();
            if (initialX != -1 || initialY != -1) {
                setPosition(initialX, initialY);
            } else {
                goToWall();
            }
            xSpring.addListener(this);
            ySpring.addListener(this);
            try {
                CommonEventManager.subscribeCommonEvent(orientationChangeReceiver);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * Move the magnet to the nearest wall
     * See {@link Builder#setShouldStickToWall(boolean)}
     */
    public void goToWall() {
        if (shouldStickToWall && !isGoingToWall) {
            isGoingToWall = true;
            if (window != null) {
                iconPosition[0] = window.getLayoutConfig().get().x;
            } else {
                return;
            }
            boolean endX = iconPosition[0] > getDisplayWidthInPx(context) / 2;
            float nearestXWall = endX ? xMaxValue : xMinValue;
            actor.removeAllListeners();
            Log.i("Magnet.goToWall([]):493    x=" + window.getLayoutConfig().get().x + "    y=" + window.getLayoutConfig().get().y);
            xSpring.setEndValue(nearestXWall);
            xSpring.setCurrentValue(window.getLayoutConfig().get().x, true);
            float velocity = iconPosition[0] > nearestXWall ? -goToWallVelocity : goToWallVelocity;

            xSpring.setVelocity(velocity);
            ySpring.setVelocity(10);
        }
        actor.addAllListeners();
    }

    /**
     * Destroys the magnet - removes the view from the WindowManager and calls
     * {@link IconCallback#onIconDestroyed()}
     */
    public void destroy() {
        if (actor != null) {
            actor.removeAllListeners();
            xSpring.setAtRest();
            ySpring.setAtRest();
        }
        if (window == null) {
            return;
        }
        window.setStatusBarVisibility(Component.HIDE);
        windowManager.destroyWindow(window);
        window = null;
        try {
            CommonEventManager.unsubscribeCommonEvent(orientationChangeReceiver);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
//        context.unregisterReceiver(orientationChangeReceiver);
        if (removeView != null) {
            removeView.destroy();
        }
        if (iconCallback != null) {
            iconCallback.onIconDestroyed();
        }
        context = null;
    }

    @Override
    public void onClick(Component view) {
        xSpring.setAtRest();
        ySpring.setAtRest();
        if (iconCallback != null) {
            if (window != null) {
                iconPosition[0] = window.getLayoutConfig().get().x;
                iconPosition[1] = window.getLayoutConfig().get().y;
            }
            iconCallback.onIconClick(view, iconPosition[0], iconPosition[1]);
        }
    }

    // SpringListener


    class OrientationChangeReceiver extends CommonEventSubscriber {


        public OrientationChangeReceiver(CommonEventSubscribeInfo subscribeInfo) {
            super(subscribeInfo);
        }

        @Override
        public void onReceiveEvent(CommonEventData commonEventData) {
            Log.i("OrientationChangeReceiver.onReceiveEvent([commonEventData]):599  接收到了广播");
            onOrientationChange();
        }
    }

    protected class MagnetImitator extends InertialImitator {

        protected MagnetImitator(MotionProperty property, int trackStrategy,
                                 int followStrategy, double minValue, double maxValue) {
            super(property, trackStrategy, followStrategy, minValue, maxValue);
        }

        /**
         * 判断悬浮窗是否能够被移除框捕获
         *
         * @param locX 悬浮窗起始X轴坐标
         * @param locY 悬浮窗起始Y轴坐标
         * @return boolean
         */
        protected boolean canSnap(float locX, float locY) {
            if (!removeView.isShowing()) {
                return false;
            }
            Component view = removeView.buttonImage;
            int[] removeViewPosition = view.getLocationOnScreen();
            if (removeView.getWindow().getLayoutConfig().isPresent()) {
                WindowManager.LayoutConfig layoutConfig = removeView.getWindow().getLayoutConfig().get();
                removeViewPosition[0] = removeViewPosition[0] + layoutConfig.x;
                removeViewPosition[1] = removeViewPosition[1] + layoutConfig.y;
            }

            double distSq = distSq(locX, locY, removeViewPosition[0] + view.getEstimatedWidth() / 2,
                    removeViewPosition[1] + view.getEstimatedHeight() / 2);
            return distSq < Math.pow(2f * view.getEstimatedWidth(), 2);
        }

        @Override
        public void constrain(TouchEvent event) {
            super.constrain(event);
            showRemoveView();
            isFlinging = false;
        }

        @Override
        public void release(TouchEvent event) {
            super.release(event);
            if (!isGoingToWall && (Math.abs(ySpring.getVelocity()) >= flingVelocityMinimum
                    || Math.abs(xSpring.getVelocity()) >= flingVelocityMinimum)) {
                isFlinging = true;
            }
            Log.i("MagnetImitator.release([event]):594   " + isFlinging);
            if (!isFlinging) {
                goToWall();
            }
            hideRemoveView();
            if (iconOverlapsWithRemoveView()) {
                Log.i("MagnetImitator.release([event]):599");
                isFlinging = false;
                if (iconCallback != null) {
                    iconCallback.onFlingAway();
                }
            }
        }


        @Override
        public void imitate(final Component view, final TouchEvent event) {
            if (window == null) {
                return;
            }
            final float viewValue = 0;
            if (mProperty == MotionProperty.X) {
                mOffset = window.getLayoutConfig().get().x - window.getLayoutConfig().get().width / 2;
            } else if (mProperty == MotionProperty.Y) {
                mOffset = window.getLayoutConfig().get().y - window.getLayoutConfig().get().height / 2;
            } else {
                return;
            }
            final float eventValue = mProperty.getValue(event);
            Log.i("MagnetImitator.imitate([view, event]):637");
            imitate(BigDecimal.valueOf(viewValue).add(BigDecimal.valueOf(mOffset)).floatValue(), eventValue, 0, event);
            if (removeView.isShowing()) {
                if (window.getLayoutConfig().isPresent()) {
                    removeView.onMove(window.getLayoutConfig().get().x, window.getLayoutConfig().get().y);
                }
            }
        }

        @Override
        public void mime(float offset, float value, float delta, float dt, TouchEvent event) {

            if (iconOverlapsWithRemoveView() && canSnap(event.getPointerScreenPosition(0).getX(), event.getPointerScreenPosition(0).getY())) {

                // snap to it - remember to compensate for translation
                int[] removeViewPosition = removeView.buttonImage.getLocationOnScreen();
                Log.i("MagnetImitator  buttonImage:" + removeViewPosition[0] + " " + removeViewPosition[1]);
                if (removeView.getWindow().getLayoutConfig().isPresent()) {
                    WindowManager.LayoutConfig config = removeView.getWindow().getLayoutConfig().get();
                    removeViewPosition[0] = removeViewPosition[0] + config.x;
                    removeViewPosition[1] = removeViewPosition[1] + config.y;

                }
                switch (mProperty) {
                    case X:
                        int midPointX = removeViewPosition[0] + removeView.buttonImage.getEstimatedWidth() / 2 - window.getLayoutConfig().get().width / 2;
                        getSpring().setCurrentValue(window.getLayoutConfig().get().x);
                        getSpring().setEndValue(midPointX);
                        break;
                    case Y:
                        int midPointY = removeViewPosition[1] + removeView.buttonImage.getEstimatedHeight() / 2 - window.getLayoutConfig().get().height / 2;
                        if (getDisplayWidthInPx(removeView.buttonImage.getContext()) > getDisplayHightInPx(removeView.buttonImage.getContext())) { //如果是横屏
                            Display display = DisplayManager.getInstance().getDefaultDisplay(removeView.buttonImage.getContext()).get();
                            if (display.getRealAttributes().height == display.getAttributes().height) { //表示获取不到状态栏高度
                                if (BaseApplication.getInstance().getStatuBarHeight() == 0) {
                                    midPointY = midPointY - AttrHelper.vp2px(24, removeView.buttonImage.getContext());
                                } else {
                                    midPointY = midPointY - BaseApplication.getInstance().getStatuBarHeight();
                                }
                            }
                        }
                        Log.i("MagnetImitator midPointY: " + midPointY + "      " + BaseApplication.getInstance().getStatuBarHeight());
                        getSpring().setCurrentValue(window.getLayoutConfig().get().y);
                        getSpring().setEndValue(midPointY);
                        break;
                }
            } else {
                Log.i("MagnetImitator.mime([offset, value, delta, dt, event]):677    " + offset);
                // follow finger
                super.mime(offset, value, delta, dt, event);
            }
        }
    }

    protected class WindowManagerPerformer extends Performer {

        /**
         * 用于判定方向
         */
        protected final MotionProperty motionProperty;

        /**
         * 构造方法
         *
         * @param motionProperty motionProperty
         */
        protected WindowManagerPerformer(MotionProperty motionProperty) {
            super(null, null);
            this.motionProperty = motionProperty;
        }


        @Override
        public void onSpringUpdate(Spring spring) {
            double currentValue = spring.getCurrentValue();
            if (currentValue < 0) {
                currentValue = 0;
            }
            if (motionProperty == MotionProperty.X) {
                layoutParams.x = (int) currentValue;
                layoutParams.y = window.getLayoutConfig().get().y;
                window.setLayoutConfig(layoutParams);
            } else if (motionProperty == MotionProperty.Y) {
                layoutParams.x = window.getLayoutConfig().get().x;
                layoutParams.y = (int) currentValue;
                window.setLayoutConfig(layoutParams);
            } else {
                return;
            }

            if (isFlinging && !isBeingDragged && iconOverlapsWithRemoveView()) {
                if (motionProperty == MotionProperty.Y) {
                    Log.i("WindowManagerPerformer.onSpringUpdate([spring]):715");
                    isFlinging = false;
                    if (iconCallback != null) {
                        iconCallback.onFlingAway();
                    }
                }
                hideRemoveView();
            }
        }

        @Override
        public void onSpringAtRest(Spring spring) {
            super.onSpringAtRest(spring);
            isGoingToWall = false;
            if (!isBeingDragged) {
                hideRemoveView();
            }
        }
    }

    /**
     * 获取屏幕宽度
     *
     * @param context 上下文
     * @return int
     */
    protected static int getDisplayWidthInPx(Context context) {
        int width = BaseApplication.getInstance().getScreenWidth();
        if (width != 0) {
            return width;
        }
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        return display.getAttributes().width;
    }

    /**
     * 获取屏幕的高度
     *
     * @param context 上下文
     * @return int
     */
    protected static int getDisplayHightInPx(Context context) {
        int height = BaseApplication.getInstance().getScreenHeight();
        if (height != 0) {
            return height;
        }
        Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        return display.getAttributes().height;
    }
}
